package com.deuwise.job.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.deuwise.common.annotation.DateTime;
import com.deuwise.common.utils.DateUtils;
import com.deuwise.common.utils.FileHelperUtils;
import com.deuwise.common.utils.R;
import com.deuwise.common.utils.Result;
import com.deuwise.common.utils.cache.Cache;
import com.deuwise.common.utils.cron.JobUtils;
import com.deuwise.common.validator.ValidatorUtils;
import com.deuwise.common.validator.group.AddGroup;
import com.deuwise.common.validator.group.UpdateGroup;
import com.deuwise.job.config.JobTask;
import com.deuwise.job.entity.JobRunLogDo;
import com.deuwise.job.entity.JobRunTime;
import com.deuwise.job.service.JobRunLogDoService;
import com.deuwise.system.controller.AbstractController;
import com.deuwise.system.entity.BackUpDo;
import com.deuwise.system.entity.LogDO;
import com.deuwise.system.service.BackUpDoService;
import com.deuwise.system.service.LogDoService;
import io.swagger.annotations.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import com.baomidou.mybatisplus.plugins.Page;
import com.deuwise.job.entity.TaskDo;
import com.deuwise.job.service.TaskDoService;

import org.quartz.Job;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.websocket.server.PathParam;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 *@author deuwise
 *@date 2018-11-26 10:50:40
 */
@Api(tags = "任务调度模块", description = "")
@RequestMapping("api/taskDo")
@RestController()
public class TaskDoController extends AbstractController {


    @Autowired
    private TaskDoService taskDoService;


    /**
     * 任务信息信息
     */
    @GetMapping("/{Id}")
    @RequiresPermissions("sys:schedule:info")
    public Result<TaskDo> info(@PathVariable("Id") String id){
        TaskDo taskDo = taskDoService.selectById(id);
        return  Result.ok(taskDo);
    }

    @ApiOperation(value = "任务list", notes = "")
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    @RequiresPermissions("sys:schedule:list")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "name", value = "任务名称", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "currentPage", value = "开始页数", defaultValue = "1", dataType = "int", paramType = "query"),
            @ApiImplicitParam(name = "pageSize", value = "每页多少条", defaultValue = "15", dataType = "int", paramType = "query")})
    public  Result<Page<TaskDo>> select(String name){
        Wrapper<TaskDo> wrapper=new EntityWrapper<>();
        wrapper.orderBy("create_time", false).orderBy("update_time", false);
        if(StringUtils.isNotBlank(name)) {
            wrapper.like("job_name", name);
        }
        Page<TaskDo> taskDoPage=taskDoService.selectPage(getPage(TaskDo.class),wrapper);
        return Result.ok(taskDoPage);
    }

    @ApiOperation("获取任务运行日志详情")
    @GetMapping("/getRunJobLog/{id}")
    public  Result<JobRunLogDo> getRunJobLog(@PathVariable("id")String id){
        JobRunLogDo jobRunLogDo= jobRunLogDoService.selectById(id);
        if(jobRunLogDo!=null){
            return Result.ok(jobRunLogDo);
        }else{
            return  Result.build(500,"获取失败");
        }
    }
    @ApiOperation("根据Corn获取最近执行5次时间的")
    @RequestMapping(value = "/getTime", method = RequestMethod.GET)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "cornStr", value = "表达式", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "jobId", value = "任务ID",  dataType = "String", paramType = "query")})
    public R getTimeByCorn(String cornStr,String jobId){

        if(StringUtils.isNotBlank(jobId)){
            Wrapper<JobRunLogDo> wrapper=new EntityWrapper<>();
            wrapper.eq("job_id",jobId).orderBy("run_time",false);
            Page<JobRunLogDo> page=new Page<>();
            page.setCurrent(1);
            page.setSize(5);
            jobRunLogDoService.selectPage(page,wrapper);
            List<JobRunTime> jobRunTimes=new ArrayList<>();
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
           List<String> dateStrings=JobUtils.getNextExecTime(cornStr,5);
            for(JobRunLogDo jobRunLogDo:page.getRecords()){
                JobRunTime jobRunTime=new JobRunTime();
                jobRunTime.setId(jobRunLogDo.getId());
                jobRunTime.setRunTime(dateFormat.format(jobRunLogDo.getRunTime()));
                jobRunTimes.add(jobRunTime);
            }
            if(jobRunTimes!=null&&jobRunTimes.size()>0) {
                jobRunTimes = jobRunTimes.stream().sorted(Comparator.comparing(JobRunTime::getRunTime)).collect(Collectors.toList());
            }
            for(String  str:dateStrings){
                JobRunTime jobRunTime=new JobRunTime();
                jobRunTime.setRunTime(str);
                jobRunTimes.add(jobRunTime);
            }
            return R.ok(jobRunTimes);
        }
        return R.ok(JobUtils.getNextExecTime(cornStr,5));
    }

    @ApiOperation(value = "新增数据")
    @RequestMapping(value = "/", method = RequestMethod.POST)
    @RequiresPermissions("sys:schedule:save")
    public R insertTaskDo(@RequestBody TaskDo taskDo){
        boolean isSuccess = false;
        ValidatorUtils.validateEntity(taskDo, AddGroup.class);
        taskDo.setJobStatus(0);
        int count=taskDoService.queryByName(taskDo.getJobName(),null);
        if(count>0){
            return R.error(200,"任务名称不能重复");
        }
        if(null == taskDo){
            return R.error(200,"新增数据失败，请稍后再试!");
        }
        taskDo.setCreateTime(new Date());
        taskDo.setUpdateTime(new Date());
        isSuccess = taskDoService.insert(taskDo);
        if (isSuccess) {
            return R.ok();
        } else {
            return R.error(200,"新增数据失败，请稍后再试!");
        }
    }

    @ApiOperation(value = "编辑数据")
    @RequestMapping(value = "/", method = RequestMethod.PUT)
    @RequiresPermissions("sys:schedule:update")
    public R updateTaskDo(@RequestBody TaskDo taskDo){
        ValidatorUtils.validateEntity(taskDo, UpdateGroup.class);
        boolean isSuccess = false;
        if(null == taskDo){
            return R.error(200,"数据编辑失败，请稍后再试!");
        }
        int count=taskDoService.queryByName(taskDo.getJobName(),taskDo);
        if(count>0){
            return R.error(200,"任务名称不能重复");
        }
        if (jobTask.checkJob(taskDo)) {
            return  R.error("已经启动法更任务无新,请停止后更新");
        }
        taskDo.setUpdateTime(new Date());
        isSuccess = taskDoService.updateById(taskDo);
        if (isSuccess) {
            return R.ok();
        } else {
            return R.error(200,"数据编辑失败，请稍后再试!");
        }
    }
    @ApiOperation(value = "删除任务", notes = "删除任务")
    @ApiImplicitParam(name = "id", value = "任务id", required = true, dataType = "String", paramType = "path")
    @DeleteMapping("/{id}")
    @RequiresPermissions("sys:schedule:delete")
    public R deleteJob(@PathVariable String id){
        if (org.apache.commons.lang3.StringUtils.isEmpty(id)) {
            return R.error("获取数据失败");
        }
        TaskDo job = taskDoService.selectById(id);
        boolean flag = jobTask.checkJob(job);
        if(job.getJobStatus()==null){
            job.setJobStatus(0);
        }
        boolean status1=(!flag &&job.getJobStatus()==1);
        boolean status2=(flag && job.getJobStatus()==0);
        if (status1|| status2) {
            return R.error("您任务表状态和web任务状态不一致,无法删除");
        }
        if (flag) {
            return R.error("该任务处于启动中，无法删除");
        }
        if(taskDoService.deleteById(id)){
            return R.ok();
        }
        else {
            return R.error();
        }
    }
    @PostMapping("/updateStatus")
    @ApiOperation(value = "更新任务状态" , notes = "根据查询条件显示任务模块")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", required = true,value = "任务id", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "status",required = true,value="任务状态",dataType="int",defaultValue = "-1",paramType = "query")
    })
    @RequiresPermissions("sys:schedule:update")
    public R startJob( @PathParam("id") String id,
                       @PathParam("status") int status) {
        try {
            if (status == 0) {
                TaskDo job = taskDoService.selectById(id);
                jobTask.remove(job);
                job.setJobStatus(0);
                taskDoService.updateById(job);
            } else {
                TaskDo job = taskDoService.selectById(id);
                jobTask.startJob(job);
                job.setJobStatus(1);
                taskDoService.updateById(job);
            }
        }catch (Exception ex){
            return  R.error("启用失败");
        }
        return  R.ok();
    }


    @ApiOperation(value = "批量删除记录")
    @RequestMapping(value = "/deleteSelect", method = RequestMethod.POST)
    @RequiresPermissions("sys:schedule:delete")
    public  R deleteSelect(@ApiParam(value = "ids集合",name = "ids",required = true) @RequestParam String[] ids){
        JSONObject jsonObject=new JSONObject();
        List<String> delFailList=new ArrayList<>();
        List<String> successList=new ArrayList<>();
        try {
            if (ids != null && ids.length > 0) {
                for (String id : ids) {
                    TaskDo job = taskDoService.selectById(id);
                    boolean flag = jobTask.checkJob(job);
                    boolean status1=(!flag &&job.getJobStatus()==1);
                    boolean status2=(flag && job.getJobStatus()==0);
                    if (status1|| status2) {
                        delFailList.add(job.getJobName());
                        continue;
                    }
                    if (flag) {
                        delFailList.add(job.getJobName());
                        continue;
                    }
                    taskDoService.deleteById(id);
                    successList.add(id);
                }
            }

        }catch (Exception ex){
            ex.printStackTrace();
        }
        jsonObject.put("failList",delFailList);
        jsonObject.put("sucessList",successList);
        return  R.ok(jsonObject);
    }

    @Autowired
    private JobTask jobTask;

    @ApiOperation(value = "立即执行")
    @PostMapping(value = "/runNowOnce")
    @ResponseBody
    @RequiresPermissions("sys:schedule:run")
    public Result<String> runNowOnce(String id) {
        try {
            TaskDo scheduleJob = taskDoService.selectById(id);
            if(scheduleJob.getJobStatus()!=1){
                return Result.ok("请先启动任务");
            }
            jobTask.runAJobNow(scheduleJob);
            return Result.ok("任务执行成功");
        } catch (Exception e) {
            System.out.println(e.toString());
        }
        return Result.ok("任务执行失败");
    }

    @Autowired
    private JobRunLogDoService jobRunLogDoService;

    @ApiOperation(value = "任务执行运行日志", notes = "任务执行运行日志")
    @ResponseBody
    @GetMapping("/jobRunList")
    @RequiresPermissions("sys:jobrunlog:list")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "name", value = "操作名称", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "startLogTime", value = "开始时间", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "endLogTime", value = "结束时间", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "runType", value = "运行方式 0 手动,1自动", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "currentPage", value = "开始页数", defaultValue = "1", dataType = "int", paramType = "query"),
            @ApiImplicitParam(name = "pageSize", value = "每页多少条", defaultValue = "15", dataType = "int", paramType = "query")})
    public Result<Page<JobRunLogDo>> jobRunList(
            @DateTime(message = "您输入的格式错误，正确的格式为：{format}")   @PathParam("startLogTime") String startLogTime,
            @DateTime(message = "您输入的格式错误，正确的格式为：{format}")   @PathParam("endLogTime") String endLogTime,
            @RequestParam(value = "name",required = false) String name,
            @RequestParam(value = "runType",required = false) String runType
    ){

        Wrapper<JobRunLogDo> wrapper=new EntityWrapper<>();
        if(name!=null&&StringUtils.isNotBlank(name)){
            wrapper.like("job_name",name);

        }
        Date startDate=null;
        Date endDate=null;
        DateFormat fmt =new SimpleDateFormat("yyyy-MM-dd");
        if(!StringUtils.isEmpty(startLogTime)){
            try {
                startDate=fmt.parse(startLogTime);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        if(!StringUtils.isEmpty(endLogTime)){
            try {
                endDate=(DateUtils.endOfDay(fmt.parse(endLogTime)));
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        if(startDate!=null){
            wrapper.gt("run_time",startDate);
        }
        if(endDate!=null){
            wrapper.lt("run_time",endDate);
        }
        if(StringUtils.isNotBlank(runType)){
          wrapper.eq("run_type",Integer.parseInt(runType));
        }
        wrapper.orderBy("run_time",false);
        Page<JobRunLogDo> page = jobRunLogDoService.selectPage(getPage(JobRunLogDo.class), wrapper);
        Result<Page<JobRunLogDo>> data=Result.ok(page);
        return  data;
    }
    @Autowired
    private LogDoService logDoService;

    @Autowired
    private BackUpDoService backUpDoService;
    @ApiOperation(value = "备份任务运行日志")
    @RequestMapping(value = "/jobRunLogBackUp", method = RequestMethod.POST)
    @RequiresPermissions("sys:jobrunlog:backup")
    public R jobRunLogBackUp(HttpServletRequest request) {
        boolean isSuccess = false;
        BackUpDo backUpDo = new BackUpDo();
        String backUrl = "";
        if (Cache.get("jobRunLogBackUpData") != null) {
            return R.error(200, "有备份任务进行中请稍后");
        }
        Cache.add("jobRunLogBackUpData", 1, 1800000);
        backUrl = logDoService.backUpLog(true);
        Cache.remove("backUpData");
        backUpDo.setBackUrl(backUrl);
        backUpDo.setSizeNum(0);
        backUpDo.setFileType(2);
        Cache.remove("jobRunLogBackUpData");
        if (backUrl == null) {
            return R.error(200, "备份任务日志文件失败!");
        }
        if (StringUtils.isNotBlank(backUrl)) {
            backUpDoService.setBackUpData(backUpDo,backUrl);
        }
        backUpDo.setCreateTime(new Date());
        if (null == backUpDo) {
            Cache.remove("jobRunLogBackUpData");
            return R.error(200, "备份任务日志文件失败!");
        }
        Cache.remove("jobRunLogBackUpData");
        isSuccess = backUpDoService.insert(backUpDo);
        if (isSuccess) {
            return R.ok();
        } else {
            return R.error(200, "备份任务日志文件失败!");
        }
    }

    @ApiOperation(value = "清理日志")
    @RequestMapping(value = "/clearJobRunLog", method = RequestMethod.POST)
    @RequiresPermissions("sys:jobrunlog:clear")
    @ApiImplicitParam(name = "month",dataType = "Integer", paramType = "query",value = "-1全部除了今天，1,3,6，12,一个月，3个月半年，一年", defaultValue = "-1")
    public R clearJobRunLog(Integer month) {
        //清理日志
        Integer days=1;
        if(month>0){
            days=month*30;
        }
        //删除日志数据库记录
        Wrapper<JobRunLogDo> logDOWrapper=new EntityWrapper<>();
        Date pointDate = new Date();
        if(month!=-1) {
            pointDate = DateUtils.addDateDays(pointDate, 0 - days);
            pointDate = DateUtils.endOfDay(pointDate);
            logDOWrapper.le("run_time", pointDate);
        }
        jobRunLogDoService.delete(logDOWrapper);
        return R.ok();
    }

    @ApiOperation(value = "下载日志")
    @GetMapping("/downLoadJobLog")
    @RequiresPermissions("sys:jobrunlog:down")
    public void downloadJobLog(HttpServletResponse response,
                           HttpServletRequest request) throws IOException {
        Wrapper<BackUpDo> backUpDoWrapper=new EntityWrapper<>();
        backUpDoWrapper.orderBy("create_time",false).eq("file_type",2);
        BackUpDo backUpDo= backUpDoService.selectOne(backUpDoWrapper);
        backUpDoService.downloadFile(response,backUpDo);

    }

}